// 要求程序运行后，给出六个菜单项的内容和输入提示
// 1. 通信录链表的建立
// 2. 通信者结点的插入
// 3. 通信者结点的查询
// 4. 通信者结点的删除
// 5. 通信录结点的输出
// 6. 退出管理系统

/***************************************/
/*     主控菜单处理测试程序 main2.c    */
/***************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct          // 定义通信录结点类型
{
  char num[5];          // 编号
  char name[9];        // 姓名
  char sex[3];            // 性别
  char phone[13];    // 电话
  char addr[31];         // 地址
} DataType;

typedef struct node // 定义结点的类型
{
  DataType data;      // 定义结点的数据域
  struct node *next; // 定义结点的指针域
} ListNode;

typedef ListNode *LinkList; // 定义LinkList
LinkList head;
ListNode *p;

// 函数声明
// int menu_select();
// LinkList CreateList(void);
// void InsertNode(LinkList head, ListNode *p);
// ListNode *ListFind(LinkList head);
// void DelNode(LinkList head);
// void PrintList(LinkList head);


/***************************************/
/*                    输出主控菜单                 */
/***************************************/
int menu_select()
{
  int sn;
  printf("欢迎进入通信录管理系统\n");
  printf("1. 通信录链表的建立\n");
  printf("2. 通信者结点的插入\n");
  printf("3. 通信者结点的查询\n");
  printf("4. 通信者结点的删除\n");
  printf("5. 通信录结点的输出\n");
  printf("0. 退出管理系统\n");
  printf("请用数字键0-5来选择菜单：");
  for(;;)
  {
    scanf("%d", &sn);
    if(sn < 0 || sn > 5)
      printf("输入错误，请重新输入：");
    else
      break;
  }  return sn;
}

/***************************************/
/*             用尾插法通信录链表             */
/***************************************/
LinkList CreateList(void)
{
  LinkList head = (LinkList)malloc(sizeof(ListNode));
  ListNode *p, *rear;
  int flag = 0; // 定义录入结束符
  rear = head;
  while (flag == 0)
  {
    // 只要录入不为 0，则不停地采用尾插法建立链表
    p = (ListNode *)malloc(sizeof(ListNode));
    printf("编号\t姓名\t性别\t电话\t\t地址\n");
    printf("------------------------------\n");
    scanf("%s\t%s\t%s\t%s\t%s", p->data.num, p->data.name, p->data.sex,p->data.phone,p->data.addr);
    rear->next = p;  // 新结点连接为尾结点的后继
    rear = p;
    printf("结束建表? (1/0)");
    scanf("%d", &flag); // 读入一个标识位到 flag
  }
  rear->next = NULL; // 建表结束，最后一个结点的指针域置为NULL
  return head;
}

/***************************************/
/*             通信者结点的插入               */
/***************************************/
void InsertNode(LinkList head, ListNode *p)
{
  ListNode *p1, *p2;
  p1 = head;
  p2 = p1->next; // p2指向第一个结点
  while(p2 != NULL && strcmp(p2->data.num, p->data.num) < 0)
  {
    p1 = p2; // p1 指向刚访问过的结点
    p2 = p2->next; // p2 指向下一个结点
  }
  p1->next = p; // 将新结点插入到 p1 之后
  p->next = p2;
}

/***************************************/
/*             通信者结点的查找               */
/***************************************/
ListNode *ListFind(LinkList head) 
{
  ListNode *p;
  char num[5];
  char name[9];
  int xz;
  printf("=================================\n");
  printf("1. 按编号查询\n");
  printf("2. 按姓名查询\n");
  printf("=================================\n");
  printf("        请选择       ");
  p = head->next;
  scanf("%d", &xz);
  if(xz == 1)
  {
    printf("请输入要查询的编号：");
    scanf("%s", num);
    while(p != NULL && strcmp(p->data.num, num) < 0)
        p = p->next;
      if (p == NULL || strcmp(p->data.num, num) > 0) 
        p = NULL;
  }
  else
  {
    if (xz == 2) 
    {
      printf("请输入要查找者的姓名：");
      scanf("%s", name);
      while(p && strcmp(p->data.name, name) != 0)
        p = p->next;
    }
  }
  return p;
}

/***************************************/
/*             通信者结点的删除               */
/***************************************/
void DelNode(LinkList head)
{
  char jx[2];
  ListNode *p, *q;
  p = ListFind(head); // 调用查找函数
  if (p == NULL)
  {
    printf("没有查找到要删除的通信者\n");
    return;
  }
  printf("确定要删除该通信者？(y / n)");
  scanf("%s", &jx);
  if (jx[0] == 'y' || jx[0] == 'Y')
  {
    q = head;
    while(q != NULL && q->next != p)
      q = q->next;
    q->next = p->next; // 删除节点
    free(p);
    printf("通信者已经被删除！\n");
  }
  else
    printf("删除操作已取消！\n");
}

/***************************************/
/*              通信录链表的输出                */
/***************************************/
void PrintList(LinkList head)
{
  ListNode *p;
  p = head->next; // 使 p 指向第一个结点
    printf("编号\t姓名\t性别\t电话\t\t地址\n");
  printf("----------------------------------------\n");
  while(p != NULL)
  {
    printf("%s\t%s\t%s\t%s\t%s\n", p->data.num, p->data.name, p->data.sex,p->data.phone,p->data.addr);
    printf("----------------------------------------\n");
    p = p->next;
  }
}

// 定义主函数
int main()
{
  for(;;)
  {
    switch(menu_select())
    {
      case 1:
        printf("***************************************\n");
        printf("*                通信录链表的建立              *\n");
        printf("***************************************\n");
        head = CreateList();
        break;
      case 2:
        printf("***************************************\n");
        printf("*                通信录结点的输入              *\n");
        printf("***************************************\n");
        printf("编号(4)  姓名(8) 性别  电话(11)  地址(31)\n");
        printf("***************************************\n");
        p = (ListNode *)malloc(sizeof(ListNode));
        scanf("%s %s %s %s %s", p->data.num, p->data.name, p->data.sex,p->data.phone,p->data.addr);
        InsertNode(head, p);
        break;
      case 3:
        printf("***************************************\n");
        printf("*                通信录结点的查询              *\n");
        printf("***************************************\n");
        p = ListFind(head);
        if(p != NULL)
        {
          printf("编号\t 姓名\t 性别\t 联系电话\t 地址\n");
          printf("----------------------------------------\n");
          printf("%s\t %s\t %s\t %s\t %s\n", p->data.num, p->data.name, p->data.sex, p->data.phone, p->data.addr);
          printf("----------------------------------------\n");
        }
        else 
          printf("没有查找到查询的通信者\n");
        break;
      case 4:
        printf("***************************************\n");
        printf("*                通信录结点的删除              *\n");
        printf("***************************************\n");
        DelNode(head);
        break;
      case 5:
        printf("***************************************\n");
        printf("*                通信录结点的输出              *\n");
        printf("***************************************\n");
        PrintList(head);
        break;
      case 0:
        printf("\t 退出管理系统\n");
      return 0;
    }
  }
  return 0;
}